package it.ipermemory;

import it.ipermemory.graphic.CustomPopup;
import it.ipermemory.graphic.GraphicBox;
import it.ipermemory.graphic.ImageButtonBox;
import it.ipermemory.graphic.ProgressDialogCustom;
import it.ipermemory.graphic.ScorePopup;
import it.ipermemory.logic.Thing;
import it.ipermemory.logic.Game;
import it.ipermemory.utilities.CreateScoreImage;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;

import org.xmlpull.v1.XmlPullParserException;

import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.app.Activity;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Typeface;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.Chronometer;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;

/**
 * Activity that represents the logic of the normal game.
 * 
 * @author Stefano Tonello (stefano.tonello8821@gmail.com)
 * @version 1.0
 */
public class GameActivity extends Activity {

	/**
	 * number of rows of the table
	 */
	private int rows;
	/**
	 * number of columns of the table
	 */
	private int columns;
	/**
	 * an object that represents the type of the game
	 */
	protected Game game;
	/**
	 * the layout of this activity
	 */
	protected TableLayout table_layout;
	/**
	 * an arraylist with the graphic boxes
	 */
	private ArrayList<GraphicBox> boxesGraphicList;
	/**
	 * represents the chronometer of the game
	 */
	protected Chronometer chrono;
	/**
	 * represents the textview of the attempts
	 */
	protected TextView attempts;
	/**
	 * represents the textview of the score
	 */
	protected TextView score;
	/**
	 * this object saves first graphic box selected
	 */
	protected GraphicBox firstGbSupport = null;
	/**
	 * this object saves last graphic box selected
	 */
	protected GraphicBox gbSupport = null;
	/**
	 * this object saves first ImageView selected
	 */
	protected ImageView ivFirstSupport = null;
	/**
	 * this object saves last ImageView selected
	 */
	protected ImageView ivSupport = null;
	/**
	 * flag to know when the chronometer has to start
	 */
	private boolean firstTouch = true;
	/**
	 * it represents the image of the back box
	 */
	protected Bitmap bitmapBackBox = null;
	/**
	 * it represents the icon to show the card of the thing
	 */
	protected Bitmap bitmapCard = null;
	/**
	 * it represents the icon disabled
	 */
	protected Bitmap bitmapCardDisabled = null;
	/**
	 * the style of the words
	 */
	private Typeface typface;
	/**
	 * flag to know if the card of the thing is shown
	 */
	protected boolean cardActivityShown = false;
	/**
	 * flag to know if the game is finished
	 */
	protected boolean endGame = false;
	/**
	 * it represents the milliseconds elapsed from the start
	 */
	protected long elapsedMilliseconds;
	/**
	 * popup to show the score of the game
	 */
	protected ScorePopup customizeDialog;
	/**
	 * it represents the resources
	 */
	protected Resources res;
	/**
	 * it represents the id of a resource
	 */
	protected int resID;
	/**
	 * the image of the first box
	 */
	protected Bitmap firstBitmap = null;
	/**
	 * the image of the second box
	 */
	protected Bitmap secondBitmap = null;
	/**
	 * object that saves the last Thing
	 */
	protected Thing thingSupport;
	/**
	 * imageButton to show the card of the thing
	 */
	protected ImageButton showImageButton;
	/**
	 * imageButton to share the score
	 */
	protected ImageButton shareScoreButton;
	/**
	 * Button to return initial activity
	 */
	protected Button newGame;
	/**
	 * id of the thing to pass
	 */
	protected int idToPass;

	/**
	 * A method to create the activity
	 */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_game);

		onCreateGameActivity();
	}

	/**
	 * A method that initializes the game screen
	 */
	protected void onCreateGameActivity() {
		prepareGame();

		rows = (int) Math.sqrt((game.getGrid().size()));
		columns = rows;

		table_layout = (TableLayout) findViewById(R.id.table_layout_game);

		TableRow row;
		int jbox = 0;
		for (int i = 0; i < rows; i++) {
			row = new TableRow(this);
			for (int j = 0; j < columns; j++) {

				ImageButtonBox t = new ImageButtonBox(this);
				t.setGraphicBox(boxesGraphicList.get(jbox));
				t.setScaleType(ScaleType.FIT_XY);
				t.setImageBitmap(bitmapBackBox);
				t.setAdjustViewBounds(true);
				t.setPadding(5, 5, 5, 5);
				t.setBackgroundColor(Color.TRANSPARENT);
				t.setSoundEffectsEnabled(false);

				t.setOnClickListener(new OnClickListener() {

					public void onClick(View v) {

						manageTouchBox(v);

					}
				});

				row.addView(t, new TableRow.LayoutParams(
						android.widget.TableRow.LayoutParams.MATCH_PARENT,
						android.widget.TableRow.LayoutParams.MATCH_PARENT, 1f));

				jbox++;
			}

			table_layout.addView(row, new TableLayout.LayoutParams(
					LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 1f));
		}

		/**
		 * the listener of the button to show the card
		 */
		showImageButton.setOnClickListener(new OnClickListener() {

			public void onClick(View v) {
				chrono.stop();
				elapsedMilliseconds = chrono.getBase()
						- SystemClock.elapsedRealtime();
				cardActivityShown = true;
				Intent intent = new Intent(GameActivity.this,
						CardActivity.class);
				intent.putExtra(Game.GAME_THING_CARD, idToPass);
				GameActivity.this.startActivity(intent);
			}
		});
		
		showImageButton.setClickable(false);

		/**
		 * the listener of the button to share the score
		 */
		shareScoreButton.setOnClickListener(new OnClickListener() {

			public void onClick(View v) {
				// View progress dialog
				ProgressDialogCustom prgbar = new ProgressDialogCustom(
						GameActivity.this);
				prgbar.show();

				// Start the thread to process the image
				Handler handler = new MyHandler(prgbar, GameActivity.this);
				CreateScoreImage save_image = new CreateScoreImage(
						GameActivity.this, handler, Integer.valueOf(game
								.getScore()));
				save_image.start();
			}
		});

		TextView att1 = (TextView) findViewById(R.id.attempts_label);
		TextView chrono1 = (TextView) findViewById(R.id.time_label);
		TextView score1 = (TextView) findViewById(R.id.score_label);

		att1.setTypeface(typface);
		attempts.setTypeface(typface);
		chrono1.setTypeface(typface);
		chrono.setTypeface(typface);
		score1.setTypeface(typface);
		score.setTypeface(typface);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.activity_game, menu);
		return true;
	}

	/**
	 * method to manage the touch of the boxes
	 * 
	 * @param v
	 *            represents the view of the game
	 */
	protected void manageTouchBox(View v) {
		if (game.getFirstBox() == null || game.getSecondBox() == null) {

			manageOnClick(v);
		}
	}

	/**
	 * method to manage the tap of the user
	 * 
	 * @param v
	 *            represents the view of the game
	 */
	protected void manageOnClick(View v) {
		if (firstTouch) {
			chrono.setBase(SystemClock.elapsedRealtime());
			chrono.start();
			firstTouch = false;
		}

		ImageButtonBox t = (ImageButtonBox) v;
		gbSupport = t.getGraphicBox();

		if (t.getGraphicBox().isUncovered() == false) {
			showBox(t);
			if (game.getFirstBox() == null) {
				gbSupport.setUncovered(true);
				game.setFirstBox(gbSupport.getLogicBox());
				firstGbSupport = gbSupport;
				ivFirstSupport = ivSupport;
				modifyImageButtons();
			} else {
				game.setSecondBox(gbSupport.getLogicBox());
				manageSecondTouch();
			}
		}
	}

	/**
	 * method to modify the imageButton to show the card of the thing
	 */
	protected void modifyImageButtons() {
		showImageButton.setClickable(false);
		showImageButton.setImageBitmap(bitmapCardDisabled);
	}

	/**
	 * set and initialize the components of the view of this activity
	 */
	protected void prepareGame() {
		newGame();

		chrono = (Chronometer) findViewById(R.id.chronometer);
		attempts = (TextView) findViewById(R.id.attempts);
		score = (TextView) findViewById(R.id.score);
		showImageButton = (ImageButton) findViewById(R.id.show_button);
		shareScoreButton = (ImageButton) findViewById(R.id.share_button);
		newGame = (Button) findViewById(R.id.new_game_button);

		typface = Typeface.createFromAsset(getAssets(), "fonts/wayoshi.ttf");
		newGame.setTypeface(typface);

		ArrayList<Thing> things = new ArrayList<Thing>();

		res = getResources();
		things = game.getParserXML().getAllThings();

		resID = res.getIdentifier("back_box", "drawable", getPackageName());
		bitmapBackBox = BitmapFactory.decodeResource(res, resID);

		resID = res.getIdentifier("show_card_disabled", "drawable",
				getPackageName());
		bitmapCardDisabled = BitmapFactory.decodeResource(res, resID);

		resID = res.getIdentifier("show_card", "drawable", getPackageName());
		bitmapCard = BitmapFactory.decodeResource(res, resID);

		boxesGraphicList = new ArrayList<GraphicBox>();

		for (int j = 0; j < things.size(); j++) {
			boxesGraphicList.add(new GraphicBox(game.getGrid().get(j * 2)));
			boxesGraphicList.add(new GraphicBox(game.getGrid().get(j * 2)));
		}

		Collections.shuffle(boxesGraphicList);
	}

	/**
	 * it starts the new game
	 */
	protected void newGame() {
		try {
			game = new Game(MainActivity.xmlParserThings);
		} catch (NotFoundException e) {
			e.printStackTrace();
		} catch (XmlPullParserException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public Bitmap getBitmapBackBox() {
		return bitmapBackBox;
	}

	protected Game getGame() {
		return game;
	}

	public void setCardActivityShown(boolean cardActivityShown) {
		this.cardActivityShown = cardActivityShown;
	}

	/**
	 * method to manage the second tap of the user
	 */
	protected void manageSecondTouch() {
		game.setAttempts(game.getAttempts() + 1);
		Integer attemptsInteger = Integer.valueOf(game.getAttempts());
		attempts.setText(attemptsInteger.toString());

		discover();
	}

	/**
	 * method to discover the image of the last box selected
	 */
	public void discover() {
		if ((firstGbSupport.getLogicBox()).equals(gbSupport.getLogicBox()) == true) {

			Handler handler = new Handler();
			handler.postDelayed(new Runnable() {
				public void run() {
					game.setScore(game.getScore() + 100);
					Integer scoreInteger = Integer.valueOf(game.getScore());
					score.setText(scoreInteger.toString());

					idToPass = gbSupport.getLogicBox().getId();
					showImageButton.setClickable(true);
					showImageButton.setImageBitmap(bitmapCard);

					actionsAfterDiscover();
					actionsToReset();

				}
			}, 1000);

		} else {
			Handler handler = new Handler();
			handler.postDelayed(new Runnable() {
				public void run() {
					ivFirstSupport.setImageBitmap(bitmapBackBox);
					ivSupport.setImageBitmap(bitmapBackBox);

					firstGbSupport.setUncovered(false);
					gbSupport.setUncovered(false);
					actionsToReset();
				}
			}, 1000);
		}
	}

	/**
	 * method that creates the popup to show the score of the game
	 */
	public void createPopup() {
		customizeDialog = new ScorePopup(this, game.getScore());
		customizeDialog.setCanceledOnTouchOutside(false);
		customizeDialog.show();
		customizeDialog
				.setOnDismissListener(new DialogInterface.OnDismissListener() {

					public void onDismiss(DialogInterface dialog) {
						shareScoreButton.setVisibility(View.VISIBLE);
						newGame.setVisibility(View.VISIBLE);
						Integer scoreInteger = Integer.valueOf(game.getScore());
						score.setText(scoreInteger.toString());
					}
				});
	}

	/**
	 * method to wrap the usual operations after the discover of a box
	 */
	public void actionsAfterDiscover() {

		game.setGuessedCouples(game.getGuessedCouples() + 1);
		if (game.getGuessedCouples() == (game.getGrid().size() / 2)) {
			chrono.stop();
			int elapsedSeconds = (int) ((SystemClock.elapsedRealtime() - chrono
					.getBase()) / 1000);
			calculateScoreToPass(elapsedSeconds);
			endGame();

			createPopup();
		}

		GameActivity.this.ivFirstSupport.setVisibility(View.INVISIBLE);
		GameActivity.this.ivSupport.setVisibility(View.INVISIBLE);
	}

	/**
	 * method to change the value of the flag that represents the end of the
	 * game
	 */
	public void endGame() {
		endGame = true;
	}

	/**
	 * method to wrap the usual actions to reset the boxes shown
	 */
	public void actionsToReset() {
		game.setFirstBox(null);
		game.setSecondBox(null);
		cardActivityShown = false;
		firstGbSupport = null;

		firstBitmap.recycle();
		secondBitmap.recycle();
	}

	/**
	 * method to show the box selected
	 * 
	 * @param ivSupport
	 *            the ImageView to show
	 */
	protected void showBox(ImageButtonBox ivSupport) {
		this.ivSupport = ivSupport;

		Thing thingSupport = game.getParserXML().getThingById(
				gbSupport.getLogicBox().getId());

		if (thingSupport == null) {
			mexError();
		} else {
			if (game.getFirstBox() == null) {
				firstBitmap = BitmapFactory.decodeResource(
						res,
						getResources().getIdentifier(thingSupport.getImage(),
								"drawable", getPackageName()));

			} else {
				secondBitmap = BitmapFactory.decodeResource(
						res,
						getResources().getIdentifier(thingSupport.getImage(),
								"drawable", getPackageName()));
			}
		}
		if (game.getFirstBox() == null) {
			ivSupport.setImageBitmap(firstBitmap);
		} else {
			ivSupport.setImageBitmap(secondBitmap);
		}

	}

	/**
	 * method to calculate the score of the game
	 * 
	 * @param elapsedSeconds
	 *            the seconds elapsed from the start of the game
	 */
	protected void calculateScoreToPass(int elapsedSeconds) {
		game.calculateScore(elapsedSeconds);
	}

	/**
	 * method to create the popup if the xml parser has problems
	 */
	protected void mexError() {
		CustomPopup cp = new CustomPopup(GameActivity.this, getResources()
				.getString(R.string.error_media_load)) {

			@Override
			public void onClick(View v) {
				this.dismiss();
				finish();
			}
		};
		cp.getNoButton().setVisibility(View.GONE);
		cp.show();
	}

	/**
	 * method to manage the operation onResume of the activity
	 */
	@Override
	protected void onResume() {
		super.onResume();

		if (cardActivityShown && !endGame) {
			chrono.setBase(SystemClock.elapsedRealtime() + elapsedMilliseconds);
			chrono.start();
		}
		if (endGame) {
			showImageButton.setClickable(false);
			showImageButton.setImageBitmap(bitmapCardDisabled);
		}
	}

	/**
	 * the method closes the current activity to return all'activity initial
	 * 
	 * @param view
	 *            object that specifies the action
	 */
	public void newGame(View view) {
		finish();
	}

	/**
	 * Class that takes care of creating a callback handler. When the thread
	 * finishes processing the image communicates all'activity, an object of
	 * this class through the completion of operations.
	 * 
	 * @author Gianluca Carlesso (gianluca.carlesso@gmail.com)
	 * @version 1.0
	 */
	private static class MyHandler extends Handler {

		/**
		 * ProgressDialog to put the caller on hold while you are working on the
		 * construction of the image to be shared
		 */
		private ProgressDialogCustom prgbar;

		/**
		 * ScoreActivity of current activity
		 */
		private GameActivity score;

		/**
		 * Constructs a new object handler
		 * 
		 * @param p
		 *            object that get a progress dialog
		 * @param s
		 *            activity that invoke this handler
		 */
		public MyHandler(ProgressDialogCustom p, GameActivity s) {
			prgbar = p;
			score = s;
		}

		/**
		 * Method that handles the return messages for activity
		 */
		@Override
		public void handleMessage(Message msg) {
			Bundle bundle = msg.getData();

			// Hide progress dialog
			prgbar.dismiss();
			if (bundle.containsKey(CreateScoreImage.ERROR_KEY)) {
				// If there is an error show a message error
				CustomPopup cp = new CustomPopup(score, score.getResources()
						.getString(R.string.error_media_load)) {

					@Override
					public void onClick(View v) {
						this.dismiss();
					}
				};

				cp.getNoButton().setVisibility(View.GONE);
				cp.show();

			} else if (bundle.containsKey(CreateScoreImage.PATH_KEY)) {
				// Image created successfully

				// Prepare intent for share activity
				String path = bundle.getString(CreateScoreImage.PATH_KEY);
				Intent share = new Intent(Intent.ACTION_SEND);
				share.setType("image/png");
				
				share.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File(path)));

				// Close progress dialog and start activity
				prgbar.dismiss();
				score.startActivityShare(share);

			}
		}
	}

	/**
	 * Method that takes care of starting the activity of Android for the
	 * sharing of network elements
	 * 
	 * @param share
	 *            information to share
	 */
	private void startActivityShare(Intent share) {
		startActivity(Intent.createChooser(share,
				getResources().getString(R.string.share_image)));
	}

}
